export function Name() { return "Nollie1"; } 
export function VendorId() { return 0x16D2; }
export function ProductId() { return 0x1F11; }
export function Publisher() { return "Nollie"; } 
export function Type() { return "Hid"; }
export function DeviceType(){return "lightingcontroller";}
/* global
shutdownColor:readonly
LightingMode:readonly
forcedColor:readonly
HLE:readonly
Mos_enable:readonly
display_mode:readonly
display_map:readonly
*/
export function ControllableParameters() 
{
	return [
		{"property":"shutdownColor", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"000000"},
		{"property":"LightingMode", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"},
		{"property":"forcedColor", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"009bde"},
		{"property":"HLE", "label":"Hardware effect", "type":"combobox", "values":["Static", "Nollie"], "default":"Static"},
		{"property":"Mos_enable","label":"Source of electricity supply", "type":"combobox", "values":["USB", "Externally"], "default":"USB"},
		{"property":"display_mode","label":"Display Mode", "type":"combobox", "values":["General", "Time", "TimeMini3", "TimeMini2", "Custom Text", "Pixel Art"], "default":"General"},
		{"property":"clock_mode","label":"Clock Mode", "type":"combobox", "values":["12-hour", "24-hour"], "default":"24-hour"},
		{"property":"display_map","label":"Display Map", "type":"combobox", "values":["GeneralPixel","GeneralPixel3","GeneralPixel2", "MoFun2", "MoFun3", "MoFun4"], "default":"GeneralPixel"},
		{"property":"custom_text", "label":"Display Mode: Custom Text", "type":"textfield", "default":"Nollie"},
		{"property":"pixelArt", "label":"Display Mode: Pixel Art", "type":"textfield", "default":"[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0],[0,0,0,0,0,1,0,0,0,0,0,1,0,1,1,0,0,0,0],[0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0],[0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1],[0,1,0,1,1,1,1,1,0,1,1,0,1,0,0,1,1,1,0],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0]]"},
		{"property":"paddingX", "label":"Padding X", "type":"textfield", "default":0, "filter":/^\d+$/},
		{"property":"paddingY", "label":"Padding Y", "type":"textfield", "default":1, "filter":/^\d+$/},
	];
}

export function onMos_enableChanged() 
{
	set_mos();
}

export function SubdeviceController() { return true; }

const ChannelLedNum =  630;
const ChannelNum =  1;
const DeviceMaxLedLimit = ChannelLedNum * ChannelNum;
const MaxLedsInPacket = 21;
const sampling_frequency = 150;
let voltage_count = 0;
let version = 0;
let ch_led_num = [];
let realtime_led_num = [];
let ChannelArray = 
[
	["Channel 1", ChannelLedNum]
];

let PIXELART = [];

const LETTERS = {
	'A':[
		[0, 0, 0, 0],
		[0, 1, 1, 0],
		[1, 0, 0, 1],
		[1, 1, 1, 1],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 0, 0, 0]
	],
	'a':[
		[0, 0, 0],
		[0, 0, 0],
		[1, 1, 0],
		[0, 0, 1],
		[1, 1, 1],
		[1, 0, 1],
		[0, 0, 0]
	],
	'B':[
		[0, 0, 0, 0],
		[1, 1, 1, 0],
		[1, 0, 0, 1],
		[1, 1, 1, 0],
		[1, 0, 0, 1],
		[1, 1, 1, 0],
		[0, 0, 0, 0]
	],
	'b':[
		[1, 0, 0, 0],
		[1, 0, 0, 0],
		[1, 1, 1, 0],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[1, 1, 1, 0],
		[0, 0, 0, 0]
	],
	'C':[
		[0, 0, 0, 0],
		[0, 1, 1, 1],
		[1, 0, 0, 0],
		[1, 0, 0, 0],
		[1, 0, 0, 0],
		[0, 1, 1, 1],
		[0, 0, 0, 0]
	],
	'c':[
		[0, 0, 0],
		[0, 0, 0],
		[0, 1, 1],
		[1, 0, 0],
		[1, 0, 0],
		[0, 1, 1],
		[0, 0, 0]
	],
	'D':[
		[0, 0, 0, 0],
		[1, 1, 1, 0],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[1, 1, 1, 0],
		[0, 0, 0, 0]
	],
	'd':[
		[0, 0, 0, 0],
		[0, 0, 0, 1],
		[0, 1, 1, 1],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 1, 1, 1],
		[0, 0, 0, 0]
	],
	'E':[
		[0, 0, 0, 0],
		[1, 1, 1, 1],
		[1, 0, 0, 0],
		[1, 1, 1, 0],
		[1, 0, 0, 0],
		[1, 1, 1, 1],
		[0, 0, 0, 0]
	],
	'e':[
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[0, 1, 1, 0],
		[1, 1, 1, 1],
		[1, 0, 0, 0],
		[0, 1, 1, 1],
		[0, 0, 0, 0]
	],
	'F':[
		[0, 0, 0, 0],
		[1, 1, 1, 1],
		[1, 0, 0, 0],
		[1, 1, 1, 0],
		[1, 0, 0, 0],
		[1, 0, 0, 0],
		[0, 0, 0, 0]
	],
	'f':[
		[0, 0, 0, 0],
		[0, 0, 1, 1],
		[0, 1, 0, 0],
		[1, 1, 1, 0],
		[0, 1, 0, 0],
		[0, 1, 0, 0],
		[0, 0, 0, 0]
	],
	'G':[
		[0, 0, 0, 0],
		[0, 1, 1, 0],
		[1, 0, 0, 1],
		[1, 0, 0, 0],
		[1, 0, 0, 1],
		[0, 1, 1, 1],
		[0, 0, 0, 0]
	],
	'g':[
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[0, 1, 1, 1],
		[1, 0, 0, 1],
		[0, 1, 1, 1],
		[0, 0, 0, 1],
		[0, 1, 1, 0]
	],
	'H':[
		[0, 0, 0, 0],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[1, 1, 1, 1],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 0, 0, 0]
	],
	'h':[
		[0, 0, 0, 0],
		[1, 0, 0, 0],
		[1, 1, 1, 0],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 0, 0, 0]
	],
	'I':[
		[0, 0, 0],
		[1, 1, 1],
		[0, 1, 0],
		[0, 1, 0],
		[0, 1, 0],
		[1, 1, 1],
		[0, 0, 0]
	],
	'i':[
		[0, 1, 0],
		[0, 0, 0],
		[1, 1, 0],
		[0, 1, 0],
		[0, 1, 0],
		[1, 1, 1],
		[0, 0, 0]
	],
	'J':[
		[0, 0, 0, 0],
		[0, 0, 0, 1],
		[0, 0, 0, 1],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 1, 1, 0],
		[0, 0, 0, 0]
	],
	'j':[
		[0, 0, 1],
		[0, 0, 0],
		[0, 0, 1],
		[0, 0, 1],
		[0, 0, 1],
		[0, 0, 1],
		[1, 1, 0]
	],
	'K':[
		[0, 0, 0, 0],
		[1, 0, 0, 1],
		[1, 0, 1, 0],
		[1, 1, 0, 0],
		[1, 0, 1, 0],
		[1, 0, 0, 1],
		[0, 0, 0, 0]
	],
	'k':[
		[0, 0, 0, 0],
		[1, 0, 0, 0],
		[1, 0, 1, 0],
		[1, 1, 0, 0],
		[1, 0, 1, 0],
		[1, 0, 0, 1],
		[0, 0, 0, 0]
	],
	'L':[
		[0, 0, 0],
		[1, 0, 0],
		[1, 0, 0],
		[1, 0, 0],
		[1, 0, 0],
		[1, 1, 1],
		[0, 0, 0]
	],
	'l':[
		[1, 1, 0],
		[0, 1, 0],
		[0, 1, 0],
		[0, 1, 0],
		[0, 1, 0],
		[1, 1, 1],
		[0, 0, 0]
	],
	'M':[
		[0, 0, 0, 0],
		[1, 0, 0, 1],
		[1, 1, 1, 1],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 0, 0, 0]
	],
	'm':[
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[1, 0, 0, 1],
		[1, 1, 1, 1],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 0, 0, 0]
	],
	'N':[
		[0, 0, 0, 0],
		[1, 0, 0, 1],
		[1, 1, 0, 1],
		[1, 0, 1, 1],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 0, 0, 0]
	],
	'n':[
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[1, 1, 1, 0],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 0, 0, 0]
	],
	'O':[
		[0, 0, 0, 0],
		[0, 1, 1, 0],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 1, 1, 0],
		[0, 0, 0, 0]
	],
	'o':[
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[0, 1, 1, 0],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 1, 1, 0],
		[0, 0, 0, 0]
	],
	'P':[
		[0, 0, 0, 0],
		[1, 1, 1, 0],
		[1, 0, 0, 1],
		[1, 1, 1, 0],
		[1, 0, 0, 0],
		[1, 0, 0, 0],
		[0, 0, 0, 0]
	],
	'p':[
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[1, 1, 1, 0],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[1, 1, 1, 0],
		[1, 0, 0, 0]
	],
	'Q':[
		[0, 0, 0, 0],
		[0, 1, 1, 0],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 1, 1, 0],
		[0, 0, 0, 1]
	],
	'q':[
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[0, 1, 1, 1],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 1, 1, 1],
		[0, 0, 0, 1]
	],
	'R':[
		[0, 0, 0, 0],
		[1, 1, 1, 0],
		[1, 0, 0, 1],
		[1, 1, 1, 0],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 0, 0, 0],
	],
	'r':[
		[0, 0, 0],
		[0, 0, 0],
		[1, 0, 1],
		[1, 1, 0],
		[1, 0, 0],
		[1, 0, 0],
		[0, 0, 0]
	],
	'S':[
		[0, 0, 0, 0],
		[0, 1, 1, 1],
		[1, 0, 0, 0],
		[0, 1, 1, 0],
		[0, 0, 0, 1],
		[1, 1, 1, 0],
		[0, 0, 0, 0]
	],
	's':[
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[0, 1, 1, 1],
		[1, 1, 0, 0],
		[0, 0, 1, 1],
		[1, 1, 1, 0],
		[0, 0, 0, 0]
	],
	'T':[
		[0, 0, 0, 0, 0],
		[1, 1, 1, 1, 1],
		[0, 0, 1, 0, 0],
		[0, 0, 1, 0, 0],
		[0, 0, 1, 0, 0],
		[0, 0, 1, 0, 0],
		[0, 0, 0, 0, 0]
	],
	't':[
		[0, 0, 0, 0],
		[0, 1, 0, 0],
		[1, 1, 1, 1],
		[0, 1, 0, 0],
		[0, 1, 0, 0],
		[0, 0, 1, 1],
		[0, 0, 0, 0]
	],
	'U':[
		[0, 0, 0, 0],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 1, 1, 0],
		[0, 0, 0, 0]
	],
	'u':[
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 1, 1, 1],
		[0, 0, 0, 0]
	],
	'V':[
		[0, 0, 0, 0],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 1, 1, 0],
		[0, 1, 1, 0],
		[0, 0, 0, 0]
	],
	'v':[
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 1, 1, 0],
		[0, 1, 1, 0],
		[0, 0, 0, 0]
	],
	'W':[
		[0, 0, 0, 0, 0],
		[1, 0, 0, 0, 1],
		[1, 0, 1, 0, 1],
		[1, 0, 1, 0, 1],
		[0, 1, 0, 1, 0],
		[0, 1, 0, 1, 0],
		[0, 0, 0, 0, 0]
	],
	'w':[
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[1, 1, 1, 1],
		[1, 0, 0, 1],
		[0, 0, 0, 0]
	],
	'X':[
		[0, 0, 0, 0],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 1, 1, 0],
		[0, 1, 0, 1],
		[1, 0, 0, 1],
		[0, 0, 0, 0]
	],
	'x':[
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[1, 0, 0, 1],
		[0, 1, 1, 0],
		[0, 1, 1, 0],
		[1, 0, 0, 1],
		[0, 0, 0, 0]
	],
	'Y':[
		[0, 0, 0],
		[1, 0, 1],
		[1, 0, 1],
		[1, 0, 1],
		[0, 1, 0],
		[0, 1, 0],
		[0, 0, 0]
	],
	'y':[
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 1, 1, 1],
		[0, 0, 0, 1],
		[0, 1, 1, 0]
	],
	'Z':[
		[0, 0, 0, 0],
		[1, 1, 1, 1],
		[0, 0, 1, 0],
		[0, 1, 0, 0],
		[1, 0, 0, 0],
		[1, 1, 1, 1],
		[0, 0, 0, 0]
	],
	'z':[
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[1, 1, 1, 1],
		[0, 0, 1, 0],
		[0, 1, 0, 0],
		[1, 1, 1, 1],
		[0, 0, 0, 0]
	],
	'`':[
		[0, 0],
		[1, 0],
		[0, 1],
		[0, 0],
		[0, 0],
		[0, 0],
		[0, 0]
	],
	'~':[
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[0, 1, 0, 1],
		[1, 0, 1, 0],
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[0, 0, 0, 0]
	],
	'!':[
		[0],
		[1],
		[1],
		[1],
		[0],
		[1],
		[0]
	],
	'@':[
		[0, 0, 0, 0, 0],
		[0, 1, 1, 1, 0],
		[1, 0, 0, 0, 1],
		[1, 0, 1, 1, 0],
		[1, 0, 0, 0, 0],
		[0, 1, 1, 1, 0],
		[0, 0, 0, 0, 0]
	],
	'#':[
		[0, 0, 0, 0, 0],
		[0, 1, 0, 1, 0],
		[1, 1, 1, 1, 1],
		[0, 1, 0, 1, 0],
		[1, 1, 1, 1, 1],
		[0, 1, 0, 1, 0],
		[0, 0, 0, 0, 0]
	],
	'$':[
		[0, 0, 0],
		[0, 1, 0],
		[0, 1, 1],
		[1, 0, 0],
		[0, 1, 1],
		[1, 1, 0],
		[0, 1, 0]
	],
	'%':[
		[0, 1, 0, 0, 0],
		[1, 0, 1, 0, 1],
		[0, 1, 0, 1, 0],
		[0, 0, 1, 0, 0],
		[0, 1, 0, 1, 0],
		[1, 0, 1, 0, 1],
		[0, 0, 0, 1, 0]
	],
	'^':[
		[0, 0, 0],
		[0, 1, 0],
		[1, 0, 1],
		[0, 0, 0],
		[0, 0, 0],
		[0, 0, 0],
		[0, 0, 0]
	],
	'&':[
		[0, 0, 0, 0, 0],
		[0, 0, 1, 1, 0],
		[0, 1, 0, 0, 0],
		[0, 1, 1, 0, 1],
		[1, 0, 0, 1, 0],
		[0, 1, 1, 0, 1],
		[0, 0, 0, 0, 0]
	],
	'*':[
		[0, 0, 0],
		[1, 0, 1],
		[0, 1, 0],
		[1, 1, 1],
		[0, 1, 0],
		[1, 0, 1],
		[0, 0, 0]
	],
	'(':[
		[0, 0],
		[0, 1],
		[1, 0],
		[1, 0],
		[1, 0],
		[0, 1],
		[0, 0]
	],
	')':[
		[0, 0],
		[1, 0],
		[0, 1],
		[0, 1],
		[0, 1],
		[1, 0],
		[0, 0]
	],
	'-':[
		[0, 0, 0],
		[0, 0, 0],
		[0, 0, 0],
		[1, 1, 1],
		[0, 0, 0],
		[0, 0, 0],
		[0, 0, 0]
	],
	'_':[
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[1, 1, 1, 1]
	],
	'=':[
		[0, 0, 0],
		[0, 0, 0],
		[1, 1, 1],
		[0, 0, 0],
		[1, 1, 1],
		[0, 0, 0],
		[0, 0, 0]
	],
	'+':[
		[0, 0, 0],
		[0, 0, 0],
		[0, 1, 0],
		[1, 1, 1],
		[0, 1, 0],
		[0, 0, 0],
		[0, 0, 0]
	],
	'[':[
		[0, 0],
		[1, 1],
		[1, 0],
		[1, 0],
		[1, 0],
		[1, 1],
		[0, 0]
	],
	'{':[
		[0, 0, 1],
		[0, 1, 0],
		[1, 0, 0],
		[1, 0, 0],
		[0, 1, 0],
		[0, 0, 1],
		[0, 0, 0]
	],
	']':[
		[0, 0],
		[1, 1],
		[0, 1],
		[0, 1],
		[0, 1],
		[1, 1],
		[0, 0]
	],
	'}':[
		[1, 0, 0],
		[0, 1, 0],
		[0, 0, 1],
		[0, 0, 1],
		[0, 1, 0],
		[1, 0, 0],
		[0, 0, 0]
	],
	'\\':[
		[0, 0, 0],
		[1, 0, 0],
		[1, 0, 0],
		[0, 1, 0],
		[0, 1, 0],
		[0, 0, 1],
		[0, 0, 0]
	],
	'|':[
		[1],
		[1],
		[1],
		[1],
		[1],
		[1],
		[0]
	],
	';':[
		[0, 0],
		[0, 0],
		[0, 0],
		[0, 1],
		[0, 0],
		[0, 1],
		[1, 0]
	],
	':':[
		[0],
		[0],
		[0],
		[1],
		[0],
		[1],
		[0]
	],
	"'":[
		[1],
		[1],
		[0],
		[0],
		[0],
		[0],
		[0]
	],
	'"':[
		[0, 0, 0],
		[1, 0, 1],
		[1, 0, 1],
		[0, 0, 0],
		[0, 0, 0],
		[0, 0, 0],
		[0, 0, 0]
	],
	',':[
		[0, 0],
		[0, 0],
		[0, 0],
		[0, 0],
		[0, 0],
		[0, 1],
		[1, 0]
	],
	'<':[
		[0, 0, 0],
		[0, 0, 1],
		[0, 1, 0],
		[1, 0, 0],
		[0, 1, 0],
		[0, 0, 1],
		[0, 0, 0]
	],
	'.':[
		[0],
		[0],
		[0],
		[0],
		[0],
		[1],
		[0]
	],
	'>':[
		[0, 0, 0],
		[1, 0, 0],
		[0, 1, 0],
		[0, 0, 1],
		[0, 1, 0],
		[1, 0, 0],
		[0, 0, 0]
	],
	'/':[
		[0, 0, 0],
		[0, 0, 1],
		[0, 1, 0],
		[0, 1, 0],
		[1, 0, 0],
		[1, 0, 0],
		[0, 0, 0]
	],
	'?':[
		[0, 0, 0],
		[1, 1, 0],
		[0, 0, 1],
		[1, 1, 0],
		[0, 0, 0],
		[1, 0, 0],
		[0, 0, 0]
	],
	'0':[
		[0, 0, 0, 0],
		[0, 1, 1, 0],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[1, 0, 0, 1],
		[0, 1, 1, 0],
		[0, 0, 0, 0]
	],
	'1':[
		[0, 0],
		[0, 1],
		[1, 1],
		[0, 1],
		[0, 1],
		[0, 1],
		[0, 0]
	],
	'2':[
		[0, 0, 0, 0],
		[0, 1, 1, 0],
		[1, 0, 0, 1],
		[0, 0, 1, 0],
		[0, 1, 0, 0],
		[1, 1, 1, 1],
		[0, 0, 0, 0]
	],
	'3':[
		[0, 0, 0, 0],
		[1, 1, 1, 0],
		[0, 0, 0, 1],
		[0, 1, 1, 0],
		[0, 0, 0, 1],
		[1, 1, 1, 0],
		[0, 0, 0, 0]
	],
	'4':[
		[0, 0, 0, 0],
		[0, 0, 0, 1],
		[0, 0, 1, 1],
		[0, 1, 0, 1],
		[1, 1, 1, 1],
		[0, 0, 0, 1],
		[0, 0, 0, 0]
	],
	'5':[
		[0, 0, 0, 0],
		[1, 1, 1, 1],
		[1, 0, 0, 0],
		[1, 1, 1, 0],
		[0, 0, 0, 1],
		[1, 1, 1, 0],
		[0, 0, 0, 0]
	],
	'6':[
		[0, 0, 0, 0],
		[0, 1, 1, 0],
		[1, 0, 0, 0],
		[1, 1, 1, 0],
		[1, 0, 0, 1],
		[0, 1, 1, 0],
		[0, 0, 0, 0]
	],
	'7':[
		[0, 0, 0, 0],
		[1, 1, 1, 1],
		[0, 0, 0, 1],
		[0, 0, 1, 0],
		[0, 1, 0, 0],
		[0, 1, 0, 0],
		[0, 0, 0, 0]
	],
	'8':[
		[0, 0, 0, 0],
		[0, 1, 1, 0],
		[1, 0, 0, 1],
		[0, 1, 1, 0],
		[1, 0, 0, 1],
		[0, 1, 1, 0],
		[0, 0, 0, 0]
	],
	'9':[
		[0, 0, 0, 0],
		[0, 1, 1, 0],
		[1, 0, 0, 1],
		[0, 1, 1, 1],
		[0, 0, 0, 1],
		[0, 1, 1, 0],
		[0, 0, 0, 0]
	],
	' ':[
		[0],
		[0],
		[0],
		[0],
		[0],
		[0],
		[0]
	]
}

const DIGITS = 
{
	'0': [
	    [1, 1, 1],
	    [1, 0, 1],
	    [1, 0, 1],
	    [1, 0, 1],
	    [0, 0, 0],
	    [1, 1, 1]
	],
	'1': [
	    [0, 1, 0],
	    [1, 1, 0],
	    [0, 1, 0],
	    [0, 1, 0],
	    [0, 0, 0],
	    [0, 1, 0]
	],
	'2': [
	    [1, 1, 1],
	    [0, 0, 1],
	    [1, 1, 1],
	    [1, 0, 0],
	    [0, 0, 0],
	    [1, 1, 1]
	],
	'3': [
	    [1, 1, 1],
	    [0, 0, 1],
	    [1, 1, 1],
	    [0, 0, 1],
	    [0, 0, 0],
	    [1, 1, 1]
	],
	'4': [
	    [1, 0, 1],
	    [1, 0, 1],
	    [1, 1, 1],
	    [0, 0, 1],
	    [0, 0, 0],
	    [0, 0, 1]
	],
	'5': [
	    [1, 1, 1],
	    [1, 0, 0],
	    [1, 1, 1],
	    [0, 0, 1],
	    [0, 0, 0],
	    [1, 1, 1]
	],
	'6': [
	    [1, 1, 1],
	    [1, 0, 0],
	    [1, 1, 1],
	    [1, 0, 1],
	    [0, 0, 0],
	    [1, 1, 1]
	],
	'7': [
	    [1, 1, 1],
	    [0, 0, 1],
	    [0, 0, 1],
	    [0, 0, 1],
	    [0, 0, 0],
	    [0, 0, 1]
	],
	'8': [
	    [1, 1, 1],
	    [1, 0, 1],
	    [1, 1, 1],
	    [1, 0, 1],
	    [0, 0, 0],
	    [1, 1, 1]
	],
	'9': [
	    [1, 1, 1],
	    [1, 0, 1],
	    [1, 1, 1],
	    [0, 0, 1],
	    [0, 0, 0],
	    [1, 1, 1]
	],
	':': [
	    [0],
	    [1],
	    [0],
	    [0],
	    [1],
	    [0]
	],
	'.':[
		    [0],
		    [0],
		    [0],
		    [0],
		    [0]	
	],
	'a':[
		[0, 1, 0],
		[1, 0, 1],
		[1, 0, 1],
		[1, 1, 1],
		[1, 0, 1],
		[1, 0, 1]
	],
	'p':[
		[1, 1, 1],
		[1, 0, 1],
		[1, 0, 1],
		[1, 1, 1],
		[1, 0, 0],
		[1, 0, 0]
	],
	'm':[
		[1, 0, 1],
		[1, 1, 1],
		[1, 0, 1],
		[1, 0, 1],
		[1, 0, 1],
		[1, 0, 1]
	],
	' ':[
		[0],
		[0],
		[0],
		[0],
		[0],
		[0],
		[0]
	]
};

const SNAKE_MAPPING = [
     0,  15,  16,  31,  32,  47,  48,  63,  64,  79,  80,  95,  96, 111, 112, 127, 128, 143, 144, 159, 160, 175, 176, 191, 192, 207, 208, 223, 224, 239, 240, 255,
     1,  14,  17,  30,  33,  46,  49,  62,  65,  78,  81,  94,  97, 110, 113, 126, 129, 142, 145, 158, 161, 174, 177, 190, 193, 206, 209, 222, 225, 238, 241, 254,
     2,  13,  18,  29,  34,  45,  50,  61,  66,  77,  82,  93,  98, 109, 114, 125, 130, 141, 146, 157, 162, 173, 178, 189, 194, 205, 210, 221, 226, 237, 242, 253,
     3,  12,  19,  28,  35,  44,  51,  60,  67,  76,  83,  92,  99, 108, 115, 124, 131, 140, 147, 156, 163, 172, 179, 188, 195, 204, 211, 220, 227, 236, 243, 252,
     4,  11,  20,  27,  36,  43,  52,  59,  68,  75,  84,  91, 100, 107, 116, 123, 132, 139, 148, 155, 164, 171, 180, 187, 196, 203, 212, 219, 228, 235, 244, 251,
     5,  10,  21,  26,  37,  42,  53,  58,  69,  74,  85,  90, 101, 106, 117, 122, 133, 138, 149, 154, 165, 170, 181, 186, 197, 202, 213, 218, 229, 234, 245, 250,
     6,   9,  22,  25,  38,  41,  54,  57,  70,  73,  86,  89, 102, 105, 118, 121, 134, 137, 150, 153, 166, 169, 182, 185, 198, 201, 214, 217, 230, 233, 246, 249,
     7,   8,  23,  24,  39,  40,  55,  56,  71,  72,  87,  88, 103, 104, 119, 120, 135, 136, 151, 152, 167, 168, 183, 184, 199, 200, 215, 216, 231, 232, 247, 248
];

const SNAKE_MAPPING_3 = [
 	 0,  15,  16,  31,  32,  47,  48,  63,  64,  79,  80,  95,  96, 111, 112, 127, 128, 143, 144, 159, 160, 175, 176, 191,
     1,  14,  17,  30,  33,  46,  49,  62,  65,  78,  81,  94,  97, 110, 113, 126, 129, 142, 145, 158, 161, 174, 177, 190,
     2,  13,  18,  29,  34,  45,  50,  61,  66,  77,  82,  93,  98, 109, 114, 125, 130, 141, 146, 157, 162, 173, 178, 189,
     3,  12,  19,  28,  35,  44,  51,  60,  67,  76,  83,  92,  99, 108, 115, 124, 131, 140, 147, 156, 163, 172, 179, 188,
     4,  11,  20,  27,  36,  43,  52,  59,  68,  75,  84,  91, 100, 107, 116, 123, 132, 139, 148, 155, 164, 171, 180, 187,
     5,  10,  21,  26,  37,  42,  53,  58,  69,  74,  85,  90, 101, 106, 117, 122, 133, 138, 149, 154, 165, 170, 181, 186,
     6,   9,  22,  25,  38,  41,  54,  57,  70,  73,  86,  89, 102, 105, 118, 121, 134, 137, 150, 153, 166, 169, 182, 185,
     7,   8,  23,  24,  39,  40,  55,  56,  71,  72,  87,  88, 103, 104, 119, 120, 135, 136, 151, 152, 167, 168, 183, 184
 ];

const SNAKE_MAPPING_2 = [
     0,  15,  16,  31,  32,  47,  48,  63,  64,  79,  80,  95,  96, 111, 112, 127,
     1,  14,  17,  30,  33,  46,  49,  62,  65,  78,  81,  94,  97, 110, 113, 126,
     2,  13,  18,  29,  34,  45,  50,  61,  66,  77,  82,  93,  98, 109, 114, 125,
     3,  12,  19,  28,  35,  44,  51,  60,  67,  76,  83,  92,  99, 108, 115, 124,
     4,  11,  20,  27,  36,  43,  52,  59,  68,  75,  84,  91, 100, 107, 116, 123,
     5,  10,  21,  26,  37,  42,  53,  58,  69,  74,  85,  90, 101, 106, 117, 122,
     6,   9,  22,  25,  38,  41,  54,  57,  70,  73,  86,  89, 102, 105, 118, 121,
     7,   8,  23,  24,  39,  40,  55,  56,  71,  72,  87,  88, 103, 104, 119, 120
  ];

const MOFUN_MAPPING_2 = [
   120, 112, 104,  96,  88,  80,  72,  64,  56,  48,  40,  32,  24,  16,   8,   0,
   121, 113, 105,  97,  89,  81,  73,  65,  57,  49,  41,  33,  25,  17,   9,   1,
   122, 114, 106,  98,  90,  82,  74,  66,  58,  50,  42,  34,  26,  18,  10,   2,
   123, 115, 107,  99,  91,  83,  75,  67,  59,  51,  43,  35,  27,  19,  11,   3,
   124, 116, 108, 100,  92,  84,  76,  68,  60,  52,  44,  36,  28,  20,  12,   4,
   125, 117, 109, 101,  93,  85,  77,  69,  61,  53,  45,  37,  29,  21,  13,   5,
   126, 118, 110, 102,  94,  86,  78,  70,  62,  54,  46,  38,  30,  22,  14,   6,
   127, 119, 111, 103,  95,  87,  79,  71,  63,  55,  47,  39,  31,  23,  15,   7
];

const MOFUN_MAPPING_3 = [
   184, 176, 168, 160, 152, 144, 136, 128, 120, 112, 104,  96,  88,  80,  72,  64,  56,  48,  40,  32,  24,  16,   8,   0,
   185, 177, 169, 161, 153, 145, 137, 129, 121, 113, 105,  97,  89,  81,  73,  65,  57,  49,  41,  33,  25,  17,   9,   1,
   186, 178, 170, 162, 154, 146, 138, 130, 122, 114, 106,  98,  90,  82,  74,  66,  58,  50,  42,  34,  26,  18,  10,   2,
   187, 179, 171, 163, 155, 147, 139, 131, 123, 115, 107,  99,  91,  83,  75,  67,  59,  51,  43,  35,  27,  19,  11,   3,
   188, 180, 172, 164, 156, 148, 140, 132, 124, 116, 108, 100,  92,  84,  76,  68,  60,  52,  44,  36,  28,  20,  12,   4,
   189, 181, 173, 165, 157, 149, 141, 133, 125, 117, 109, 101,  93,  85,  77,  69,  61,  53,  45,  37,  29,  21,  13,   5,
   190, 182, 174, 166, 158, 150, 142, 134, 126, 118, 110, 102,  94,  86,  78,  70,  62,  54,  46,  38,  30,  22,  14,   6,
   191, 183, 175, 167, 159, 151, 143, 135, 127, 119, 111, 103,  95,  87,  79,  71,  63,  55,  47,  39,  31,  23,  15,   7
  ];

const MOFUN_MAPPING_4 = [
   248, 240, 232, 224, 216, 208, 200, 192, 184, 176, 168, 160, 152, 144, 136, 128, 120, 112, 104,  96,  88,  80,  72,  64,  56,  48,  40,  32,  24,  16,   8,   0,
   249, 241, 233, 225, 217, 209, 201, 193, 185, 177, 169, 161, 153, 145, 137, 129, 121, 113, 105,  97,  89,  81,  73,  65,  57,  49,  41,  33,  25,  17,   9,   1,
   250, 242, 234, 226, 218, 210, 202, 194, 186, 178, 170, 162, 154, 146, 138, 130, 122, 114, 106,  98,  90,  82,  74,  66,  58,  50,  42,  34,  26,  18,  10,   2,
   251, 243, 235, 227, 219, 211, 203, 195, 187, 179, 171, 163, 155, 147, 139, 131, 123, 115, 107,  99,  91,  83,  75,  67,  59,  51,  43,  35,  27,  19,  11,   3,
   252, 244, 236, 228, 220, 212, 204, 196, 188, 180, 172, 164, 156, 148, 140, 132, 124, 116, 108, 100,  92,  84,  76,  68,  60,  52,  44,  36,  28,  20,  12,   4,
   253, 245, 237, 229, 221, 213, 205, 197, 189, 181, 173, 165, 157, 149, 141, 133, 125, 117, 109, 101,  93,  85,  77,  69,  61,  53,  45,  37,  29,  21,  13,   5,
   254, 246, 238, 230, 222, 214, 206, 198, 190, 182, 174, 166, 158, 150, 142, 134, 126, 118, 110, 102,  94,  86,  78,  70,  62,  54,  46,  38,  30,  22,  14,   6,
   255, 247, 239, 231, 223, 215, 207, 199, 191, 183, 175, 167, 159, 151, 143, 135, 127, 119, 111, 103,  95,  87,  79,  71,  63,  55,  47,  39,  31,  23,  15,   7
];

export function onpixelArtChanged()
{
	if (display_mode == 'Pixel Art')
	{
		try
		{			
			PIXELART = JSON.parse(pixelArt);
			device.log('Pixel Art Updated!');
		}
		catch(ex)
		{
			device.log(ex.message);
		}
	}
}

export function ondisplay_modeChanged()
{
	if (display_mode == 'Pixel Art')
	{
		try
		{			
			PIXELART = JSON.parse(pixelArt);
			device.log('Pixel Art Updated!');
		}
		catch(ex)
		{
			device.log(ex.message);
		}
	}
}

let display = new Array(8 * 32).fill(0); 
let snakeDisplayMap;

function insertDigitIntoDisplay( digit, startCol) 
{
	const mapRow = snakeDisplayMap.length / 8;
    for (let row = 0; row < digit.length; row++) 
    {
        for (let col = 0; col < digit[row].length; col++) 
        {
        	let index = (row * mapRow + (mapRow * paddingY)) + startCol + col + parseInt(paddingX);

            if (index < 8 * 32) 
            {  
                display[index] = digit[row][col];
            }
        }
    }
}

function insertPixelArtIntoDisplay(art)
{
	for (let row = 0; row < art.length; row++)
	{
		for (let col = 0; col < art[row].length; col++)
		{
			let index = (row * displaySize.width + (displaySize.width * (paddingY - 1))) + displaySize.width + col + parseInt(paddingX);

			if (index < displaySize.height * displaySize.width) 
			{  
				display[index] = art[row][col];
			}
		}
	}
}

function rearrangeDisplay_init() 
{
	if(display_map == "MoFun2")
	{	
		snakeDisplayMap = MOFUN_MAPPING_2;
	}
	else if(display_map == "MoFun3")
	{
		snakeDisplayMap = MOFUN_MAPPING_3;
	}
	else if(display_map == "MoFun4")
	{
		snakeDisplayMap = MOFUN_MAPPING_4;
	}
	else if(display_map == "GeneralPixel3")
	{
		snakeDisplayMap = SNAKE_MAPPING_3;
	}	
	else if(display_map == "GeneralPixel2")
	{
		snakeDisplayMap = SNAKE_MAPPING_2;
	}	
	else
	{
		snakeDisplayMap = SNAKE_MAPPING;
	}
}

function rearrangeDisplayForSnakeLayout() 
{
    const snakeDisplay = new Array(display.length);

    for (let i = 0; i < snakeDisplayMap.length; i++) 
    {
    	snakeDisplay[snakeDisplayMap[i]] = display[i];
    }
    return snakeDisplay;
}

function displayClock() 
{
	display.fill(0);
	const now = new Date();
    var hours = now.getHours();
	var hours12 = now.getHours();
	var minutes = now.getMinutes();
	var seconds = now.getSeconds();
	var ampm = 'am';

	if (clock_mode == "12-hour") 
	{
		if (hours12 == 0) { hours12 = 12; }
		if (hours12 > 12) { hours12 = hours12 - 12;}
		if (hours >= 12) { ampm = 'pm'; }

		hours = (hours12 < 10) ? '0' + hours12 : hours12;
		minutes = (minutes < 10) ? '0' + minutes : minutes;
		seconds = (seconds < 10) ? '0' + seconds : seconds;
	}

	hours = String(hours).padStart(2, '0');
	minutes = String(minutes).padStart(2, '0');
	seconds = String(seconds).padStart(2, '0');

    let timeDigits;
	switch(display_mode)
	{
		case 'TimeMini3':
			if (clock_mode == '12-hour')
			{
				timeDigits = hours  + minutes  + ampm;
			}
			else
			{
				timeDigits = hours  + minutes  + seconds;
			}
			break;
		case 'TimeMini2':
			timeDigits = hours + minutes;
			break;
		case 'Time':
			if (clock_mode == '12-hour')
			{
				if (now.getSeconds() % 2 !== 0) 
				{
					timeDigits = hours + '.' + minutes + ampm;
				} 
				else 
				{
					timeDigits = hours + ':' + minutes + ampm;
				}
			}
			else
			{
				if (now.getSeconds() % 2 !== 0) 
				{
					timeDigits = hours + '.' + minutes + '.' + seconds;
				} 
				else 
				{
					timeDigits = hours + ':' + minutes + ':' + seconds;
				}
			}
			break;
		case 'Pixel Art':
			timeDigits = 'Pixel Art';
			break;
		default:
			timeDigits = custom_text;
	}

    let colOffset = 0;
    for (const digit of timeDigits) 
    {
		switch(display_mode)
		{
			case 'TimeMini2':
			case 'TimeMini3':
				insertDigitIntoDisplay(DIGITS[digit], colOffset);
				colOffset += 4; 
				break;
			case 'Time':
				insertDigitIntoDisplay(DIGITS[digit], colOffset);
				if(digit == ":" || digit == ".")
				{
					colOffset += 2;  
					
				}
				else
				{
					colOffset += 4; 
				}
				break;
			case 'Pixel Art':
				insertPixelArtIntoDisplay(PIXELART);
				break;
			default:
				insertDigitIntoDisplay(LETTERS[digit], colOffset);
				switch(digit)
				{
					case ' ':
						colOffset += 1;
						break;
					case '!':
					case '|':
					case ':':
					case "'":
					case '.':
						colOffset += 2;
						break;
					case '`':
					case '(':
					case ')':
					case '[':
					case ']':
					case ';':
					case ',':
					case '1':
						colOffset += 3;
						break;
					case 'a':
					case 'c':
					case 'I':
					case 'i':
					case 'j':
					case 'L':
					case 'l':
					case 'r':
					case 'Y':
					case '$':
					case '^':
					case '*':
					case '-':
					case '=':
					case '+':
					case '{':
					case '}':
					case '\\':
					case '"':
					case '<':
					case '>':
					case '/':
					case '?':
						colOffset += 4;
						break;
					case 'T':
					case 'W':
					case '@':
					case '#':
					case '%':
					case '&':
						colOffset += 6;
						break;
					default:
						colOffset += 5;
				}
		}
    }
}

function SetupChannels()
{
	device.SetLedLimit(DeviceMaxLedLimit);

	for(let i = 0; i < ChannelArray.length; i++)
	{
		device.addChannel(ChannelArray[i][0], ChannelArray[i][1]);
	}
}

export function Initialize() 
{
	SetupChannels();
	get_version();
	init_ch_led_num();
	set_hardware_effect();
    device.setFrameRateTarget(60);

	if (display_mode == 'Pixel Art')
	{
		try
		{			
			PIXELART = JSON.parse(pixelArt);
			device.log('Pixel Art Updated!');
		}
		catch(ex)
		{
			device.log(ex.message);
		}
	}
}

function get_version()
{
	var packet = new Array(65).fill(0);
	packet[1] = 0xFC;
	packet[2] = 0x01;
	device.flush();
	device.write(packet, 65);
	var config = device.read(packet, 65);
	version = config[2];
	device.log("Version: "+ version);
}

function init_ch_led_num()
{
	var packet = new Array(65).fill(0);
	packet[1] = 0xFC;
	packet[2] = 0x03;
	device.flush();
	device.write(packet, 65);
	var config = device.read(packet, 65);
	for (var i = 0; i < ChannelNum; i++) 
	{
		ch_led_num[i] = config[(i*2)] * 256 + config[1+(i*2)]; 
	}
	device.log("Channel led count: "+ ch_led_num);
}

function ch_led_num_callback()
{
	if(areArraysEqual(ch_led_num, realtime_led_num) == false)
	{
		ch_led_num = realtime_led_num.slice();
		var packet = new Array(65).fill(0);
	  	packet[1] = 0xFE;
	  	packet[2] = 0x03;
	  	for (var i = 0; i < ch_led_num.length; i++) 
	  	{
		  	let { high, low } = splitHex(ch_led_num[i]);
		  	packet[3+(i*2)] = low;
		  	packet[4+(i*2)] = high;
	 	}
	  	device.write(packet, 65);
		device.log("Update channel LED count: "+ ch_led_num);
	}	
}

export function Render() 
{
	for(let i = 0; i < ChannelArray.length; i++)
	{
		let led_num = SendChannel(i);
		realtime_led_num[i] = led_num;
	}
	ch_led_num_callback();
}

export function Shutdown() 
{
	for(let i = 0; i < ChannelArray.length; i++)
	{
		SendChannel(i, true);
	}
	set_hardware_effect(true);
}

function SendChannel(Channel, shutdown = false) 
{
	let ChannelLedCount = device.channel(ChannelArray[Channel][0]).ledCount > ChannelArray[Channel][1] ? ChannelArray[Channel][1] : device.channel(ChannelArray[Channel][0]).ledCount;
	let componentChannel = device.channel(ChannelArray[Channel][0]); 
	let RGBData = [];
	if(shutdown)
	{

		RGBData = device.createColorArray(shutdownColor, ChannelLedCount, "Inline", "GRB");
		
	}
	else if(LightingMode === "Forced") 
	{
		
		RGBData = device.createColorArray(forcedColor, ChannelLedCount, "Inline", "GRB");
	}
	else if(componentChannel.shouldPulseColors()) 
	{
		ChannelLedCount = ChannelLedNum;
		
		let pulseColor = device.getChannelPulseColor(ChannelArray[Channel][0], ChannelLedCount);
		RGBData = device.createColorArray(pulseColor, ChannelLedCount, "Inline", "GRB");
	}
	else
	{
		RGBData = device.channel(ChannelArray[Channel][0]).getColors("Inline", "GRB");
	}

	let NumPackets = Math.ceil(ChannelLedCount / MaxLedsInPacket);

 	if(display_mode != "General")
 	{
 		rearrangeDisplay_init();
		displayClock();	
		let Snake_display = rearrangeDisplayForSnakeLayout();
		for(let led_index = 0; led_index < Snake_display.length;led_index++)
		{
			if(Snake_display[led_index] == 0)
			{
				RGBData[led_index * 3] = 0;
				RGBData[led_index * 3 + 1] = 0;
				RGBData[led_index * 3 + 2] = 0;
			}	
		}	
 	}	

	for(let CurrPacket = 0; CurrPacket < NumPackets; CurrPacket++)
	{
		let packet = [0x00, CurrPacket+Channel*6];
		packet.push(...RGBData.splice(0, 63));
		device.write(packet, 65);
	}
	return ChannelLedCount;
}

function set_hardware_effect(shutdown = false)
{
	// if(HLE === "Static")
	// {
	// 	let RGBData = [];
	// 	RGBData = device.createColorArray(shutdownColor, 1, "Inline");	
	// 	let packet = [0x00,0xfe,0x02,0x00,RGBData[0],RGBData[1],RGBData[2],0x64,0x0a,0x00,0x01];
	// 	device.write(packet, 65);
	// 	device.pause(1);
	// 	device.log("set Static");
	// }
	// if(shutdown)
	// {
	// 	let packet = [0x00,0xfe,0x01,0x00];
	// 	device.write(packet, 65);
	// }	
}

function set_mos()
{
	let packet = []; 
	if(Mos_enable === "USB")
	{
		packet = [0x00,0xfe,0x1A,0x00];
	}	
	else
	{
		packet = [0x00,0xfe,0x1A,0x01];
	}	
	
	device.write(packet, 65);
	device.log("set mos");
}

function splitHex(num) 
{
  const high = (num >>> 8) & 0xFF; // 取高 8 位，并且将低 24 位清零
  const low = num & 0xFF; // 取低 8 位
  // const chk = high ^ low ^ 0x55; // 计算校验值
  return { high, low }; // 返回高位、低位和校验值的整数
}

function areArraysEqual(arr1, arr2) 
{
    return arr1.length === arr2.length && arr1.every((value, index) => value === arr2[index]);
}

function buildUInt16(lowByte, highByte) 
{
    return (lowByte & 0xFF) | ((highByte & 0xFF) << 8);
}

export function Validate(endpoint)
{
	return endpoint.interface === 0;
}

export function ImageUrl()
{
	return "https://gitee.com/cnn123666/nollie-controller/raw/master/Image/NOLLIE-RGB-600.png";
}